package com.cmdi.mq.service.impl;

import com.alibaba.fastjson.JSON;
import com.alibaba.fastjson.JSONArray;
import com.alibaba.fastjson.JSONObject;
import com.cmdi.mq.constant.SecurityConstants;
import com.cmdi.mq.domain.JwtToken;
import com.cmdi.mq.domain.LoginResult;
import com.cmdi.mq.domain.SysMenu;
import com.cmdi.mq.domain.SysUser;
import com.cmdi.mq.exception.CustomCmdiAdminException;
import com.cmdi.mq.feign.OAuth2FeignClient;
import com.cmdi.mq.mapper.SysMenuMapper;
import com.cmdi.mq.service.SysLoginService;
import com.cmdi.mq.service.SysUserService;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.data.redis.core.RedisTemplate;
import org.springframework.http.HttpStatus;
import org.springframework.http.ResponseEntity;
import org.springframework.security.core.authority.SimpleGrantedAuthority;
import org.springframework.security.jwt.JwtHelper;
import org.springframework.stereotype.Service;

import java.util.List;
import java.util.concurrent.TimeUnit;
import java.util.stream.Collectors;

/**
 * @Description: SysLoginServiceImpl
 * @Author: gaozb
 */
@Service
public class SysLoginServiceImpl implements SysLoginService {
    @Value("${custom.oauth2.clientid:null}")
    private String clientId;
    @Value("${custom.oauth2.clientsecret:null}")
    private String clientSecret;
    @Autowired
    private OAuth2FeignClient oAuth2FeignClient;
    @Autowired
    private RedisTemplate redisTemplate;
    @Autowired
    private SysMenuMapper sysMenuMapper;
    @Autowired
    private SysUserService sysUserService;
    @Override
    public LoginResult login(String username, String password, String loginType) {
        ResponseEntity<JwtToken> tokenResponseEntity = oAuth2FeignClient.getToken("password",
                username, password,
                loginType,
                clientId, clientSecret,
                null);
        HttpStatus statusCode = tokenResponseEntity.getStatusCode();
        JwtToken jwtToken = tokenResponseEntity.getBody();
        if(statusCode == HttpStatus.NOT_ACCEPTABLE
            && "-1".equalsIgnoreCase(jwtToken.getAccessToken())) {
            //经过feign fallback处理后
            throw new CustomCmdiAdminException(jwtToken.getUserInfo());
        }

        if(statusCode != HttpStatus.OK) {
            throw new CustomCmdiAdminException("调用服务未知错误");
        }

        return generateLoginResult(jwtToken);
    }

    @Override
    public LoginResult refreshToken(String refreshtoken, String loginType) {
        System.out.println(refreshtoken);
        ResponseEntity<JwtToken> tokenResponseEntity = oAuth2FeignClient.getToken("refresh_token",
                null, null,
                loginType,
                clientId, clientSecret,
                refreshtoken);
        HttpStatus statusCode = tokenResponseEntity.getStatusCode();
        JwtToken jwtToken = tokenResponseEntity.getBody();
        if(statusCode == HttpStatus.NOT_ACCEPTABLE
                && "-1".equalsIgnoreCase(jwtToken.getAccessToken())) {
            //经过feign fallback处理后
            throw new CustomCmdiAdminException(jwtToken.getUserInfo());
        }
        if(statusCode != HttpStatus.OK) {
            throw new CustomCmdiAdminException("调用服务未知错误");
        }

        return generateLoginResult(jwtToken);
    }

    private LoginResult generateLoginResult(JwtToken jwtToken) {
        String accessToken = jwtToken.getAccessToken();
        JSONObject jwtJson = JSON.parseObject(JwtHelper.decode(accessToken).getClaims());
        String userName = jwtJson.getString("user_name");
        List<SysMenu> menus = sysMenuMapper.selectMenusByUserName(userName);
        JSONArray authoritiesArray = jwtJson.getJSONArray("authorities");
        List<SimpleGrantedAuthority> authorities = authoritiesArray.stream().map(authorize -> new SimpleGrantedAuthority(authorize.toString())).collect(Collectors.toList());
        String key = SecurityConstants.TOKEN_REDIS_PREFIX + ":" + userName + ":" + accessToken;
        redisTemplate.opsForValue().set(key, "", jwtToken.getExpiresIn(), TimeUnit.SECONDS);
        SysUser person = sysUserService.getUserByUserName(userName);
        // 返回前端的数据，需要加bearer
        LoginResult loginResult = new LoginResult(jwtToken.getTokenType() + " " + accessToken,
                jwtToken.getRefreshToken(),
                menus,
                authorities,
                person,
                jwtToken.getExpiresIn()
        );
        return loginResult;
    }
}